////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file   CollabRCBot\WordChoiceGene.h
///
/// @brief  Declares the CollabRC::Bot::AI::WordChoiceGene class
////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#include "ComputationalTreeNode.h"
#include "Diff.h"
#include "Gene.h"
#include "WordSet.h"
#include "ComputationalTreeNodeVisitor.h"
#include <QtCore/QHash>
#include <QtCore/QReadWriteLock>

#define MAX_WORDLIST_MUTATIONS 50

namespace CollabRC
{
    namespace Bot
    {
        namespace AI
        {
            /**
             * @brief Implementation of a Gene which analyzes added words
             * and computes a vandalism score.
             *
             * The word list is mutable and crossable. Additionally, each
             * word in the word list has an associated weight to be able to
             * compute a weighted sum of the words. 
             * 
             * The algorithm to compute a final score based off the word counts
             * is a generic, mutable algorithm. The inputs to the algorithm are
             * the weighted sum and the number of matched words divided by the
             * number of words in the word list.
             * @version $Id$
             * @author Matthew P. Del Buono
             */
            class WordChoiceGene : public Gene
            {
            private:
                QHash<QString, float> m_wordSet;
                mutable float m_weightedSum;
                mutable float m_wordPresence;
            private:
                ComputationalTreeNode* m_algorithm;

                /**
                 * A list of words that have been recently seen
                 * by WordChoiceGene objects. When reading or writing,
                 * be sure to obtain an appropriate lock on recentWordsLock.
                 */
                static QSet<QString> recentWords;

                /**
                 * A reader-writer lock for \c recentWords. Many threads
                 * may obtain a read lock on the object at the same time,
                 * however only one write lock may be held on the object
                 * at a time. Additionally, a write lock cannot be held
                 * while any read lock is held.
                 */
                static QReadWriteLock recentWordsLock;

                /// Disallow use of the assignment operator
                const WordChoiceGene& operator =(const WordChoiceGene&);

                /**
                 * @brief Implementation of a ComputationalTreeNodeVisitor
                 * which updates the algorithms to point to the current 
                 * object.
                 *
                 * The visitor is passed through all branches of the algorithm
                 * to update the member variables to the new object.
                 * @version $Id$
                 * @author Matthew P. Del Buono
                 */
                class UpdateAlgorithmVisitor : public ComputationalTreeNodeVisitor
                {
                private:
                    WordChoiceGene& m_object;
                    /// Disallow use of the assignment operator
                    const UpdateAlgorithmVisitor& operator =(const UpdateAlgorithmVisitor&);
                public:
                    UpdateAlgorithmVisitor(WordChoiceGene& object);
                    virtual void Visit(MemberVariableTreeNode<WordChoiceGene, float>& visitor);
                };
            protected:
                ComputationalTreeNode* CreateRandomDefaultAlgorithm();

                /**
                 * @brief Creates a new algorithm based off the weighted sum and 
                 * word presence using the specified operation in a random order.
                 * @tparam T the operation with which to combine the parameters
                 * @warning The operation is created on the heap and must be tracked and 
                 * freed by the caller
                 */
                template <class T>
                inline T* CreateDefaultAlgorithm()
                {
                    MemberVariableTreeNode<WordChoiceGene, float> weightedSum(*this, &WordChoiceGene::m_weightedSum);
                    MemberVariableTreeNode<WordChoiceGene, float> wordPresence(*this, &WordChoiceGene::m_wordPresence);

                    T* newT = new T(weightedSum, wordPresence); // She turned me into a newt!
                    return newT;                                // ...I got better :(
                }
                virtual float ComputeWeightedSum(const Diff& diff) const;
                virtual float ComputeWordPresence(const Diff& diff) const;
                WordChoiceGene(ComputationalTreeNode* algorithm);
            public:
                WordChoiceGene(const WordSet& set);
                WordChoiceGene(const WordChoiceGene& copy);
                virtual ~WordChoiceGene(void);

                virtual float Test(const Diff& diff) const;
                virtual Gene* Cross(const Gene& gene) const;
                virtual Gene* Mutate() const;
            };
        }
    }
}
